package com.hzp.net.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class NioNettyServer {

    protected static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors() * 2;
    protected static final int BIZTHREADSIZE = 4;
    private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);
    private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);
    private ServerBootstrap server = new ServerBootstrap();

    private int port;

    private boolean started = false;

    public NioNettyServer(Integer port){
        // 首先，netty通过ServerBootstrap启动服务端
        //第1步定义两个线程组，用来处理客户端通道的accept和读写事件
        //parentGroup用来处理accept事件，childgroup用来处理通道的读写事件
        //parentGroup获取客户端连接，连接接收到之后再将连接转发给childgroup去处理
        server.group(bossGroup, workerGroup);

        //用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。
        //用来初始化服务端可连接队列
        //服务端处理客户端连接请求是按顺序处理的，所以同一时间只能处理一个客户端连接，多个客户端来的时候，服务端将不能处理的客户端连接请求放在队列中等待处理，backlog参数指定了队列的大小。
        server.option(ChannelOption.SO_BACKLOG, 128);

        //第2步绑定服务端通道
        server.channel(NioServerSocketChannel.class);

        //第3步绑定handler，处理读写事件，ChannelInitializer是给通道初始化
        server.childHandler(new ServerChannelInitializer());

        this.port = port;

    }

    public void start(){
        try {
        //第4步绑定端口
            ChannelFuture future = server.bind(port).sync();
            //当通道关闭了，就继续往下走
            future.channel().closeFuture().sync();
            log.info("服务端({})启动成功",this.port);
            this.started = true;
        } catch (InterruptedException e) {
            log.info("服务端({})启动失败",this.port);
        } finally {
            this.shutdown();
        }
    }

    public void shutdown(){
        try {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            this.started = false;
        } catch (InterruptedException e) {
        }

    }

    public static void main(String[] args){
        new NioNettyServer(888).start();
    }
}
